package com.itheima.redbaby.utils;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.HashMap;

/**
 * 软应用对象集合
 * 
 * @author l
 * 
 * @param <K>
 * @param <V>
 */
public class SoftMap<K, V> extends HashMap<K, V> {
	// 降低对象的引用级别
	// 将V的应用级别降低到软引用对象

	// 该集合放置的是袋子强引用对象
	private HashMap<K, MySoftValue<V>> temp;
	// 存放空袋子的引用
	private ReferenceQueue<V> queue;

	public SoftMap() {
		// 降低对象引用级别的核心方法
		Object o = new Object();
		SoftReference sr = new SoftReference(o);

		// 工作内容
		// 1、将占用内存较多的手机装到袋子中（put，get……）
		// 2、清理没用的空袋子
		temp = new HashMap<K, MySoftValue<V>>();
		queue=new ReferenceQueue<V>();
	}

	@Override
	public V put(K key, V value) {
		MySoftValue<V> sr = new MySoftValue<V>(key,value,queue);
		temp.put(key, sr);
		return null;
	}

	@Override
	public V get(Object key) {
		clearNullSoftReference();
		MySoftValue<V> sr = temp.get(key);
		if (sr != null) {
			// 垃圾回收器清除，则此方法将返回 null
			return sr.get();
		}
		return null;
	}

	@Override
	public boolean containsKey(Object key) {
		clearNullSoftReference();
		// 什么才叫真正的含有
		MySoftValue<V> sr = temp.get(key);
		if (sr != null) {
			if (sr.get() != null) {
				return true;
			}
			// return sr.get()!=null;
		}
		return false;
	}
	/**
	 * 清理空袋子
	 */
	private void clearNullSoftReference() {
		// 方式一：循环装袋子的集合（temp），检查那个是空袋子，如果是空删除
		/**
		 * for(Map.Entry<K,V> item:temp.entrySet()) { item.getValue().get(); }
		 */
		// 绝大多数的情况下，内存充足时没有对象被删除，该循环==无用功
		// 方式二：如果能够直接知道temp中谁是空袋子
		// 到底谁最了解空袋子？GC（小偷）——在偷手机的时候记录账，把那个“袋子”手机给投注
		// 查账——我们提供
		
		// 轮询此队列，查看是否存在可用的引用对象。如果存在"一个"立即可用的对象，则从该队列中"移除"此对象并返回。否则此方法立即返回 null。 
		MySoftValue<V> sr = (MySoftValue<V>) queue.poll();
		while(sr!=null)
		{
			// 删除
			temp.remove(sr.key);
			sr = (MySoftValue<V>) queue.poll();
		}
		
	}
	/**
	 * 加强板袋子（为袋子增加了一个标签）
	 * @author l
	 *
	 * @param <V>
	 */
	private class MySoftValue<V> extends SoftReference<V>{
		Object key;

		public MySoftValue(Object key,V referent,ReferenceQueue<? super V> q) {
			// SoftReference(T referent, ReferenceQueue<? super T> q) 
			super(referent,q);
			this.key = key;
		}
		
	}
}
